/* Copyright (C) 1991,1993,1995,1997,1998,2003,2004
   Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by Torbjorn Granlund (tege@sics.se).

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include "api.h"

#define op_t  unsigned long int
#define OPSIZ (sizeof(op_t))

typedef unsigned char byte;

void* memset(void* dstpp, int c, size_t len) {
    long int dstp = (long int)dstpp;

    if (len >= 8) {
        int xlen;
        op_t cccc;

        cccc = (unsigned char)c;
        cccc |= cccc << 8;
        cccc |= cccc << 16;
        if (OPSIZ > 4) {
            /* Do the shift in two steps to avoid warning if long has 32 bits.  */
            cccc |= (cccc << 16) << 16;
        }

        /* There are at least some bytes to set.
       No need to test for LEN == 0 in this alignment loop.  */
        while (dstp % OPSIZ != 0) {
            ((byte*)dstp)[0] = c;
            dstp += 1;
            len -= 1;
        }

        /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */
        xlen = len / (OPSIZ * 8);
        while (xlen > 0) {
            ((op_t*)dstp)[0] = cccc;
            ((op_t*)dstp)[1] = cccc;
            ((op_t*)dstp)[2] = cccc;
            ((op_t*)dstp)[3] = cccc;
            ((op_t*)dstp)[4] = cccc;
            ((op_t*)dstp)[5] = cccc;
            ((op_t*)dstp)[6] = cccc;
            ((op_t*)dstp)[7] = cccc;
            dstp += 8 * OPSIZ;
            xlen -= 1;
        }
        len %= OPSIZ * 8;

        /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */
        xlen = len / OPSIZ;
        while (xlen > 0) {
            ((op_t*)dstp)[0] = cccc;
            dstp += OPSIZ;
            xlen -= 1;
        }
        len %= OPSIZ;
    }

    /* Write the last few bytes.  */
    while (len > 0) {
        ((byte*)dstp)[0] = c;
        dstp += 1;
        len -= 1;
    }

    return dstpp;
}
